"""
Bilibili (B站) automation implementation - Login Only

Supports cookie-based multi-account login for Bilibili.
Based on Selenium automation similar to Xiaohongshu implementation.
"""
from __future__ import annotations

import json
import os
import time
from dataclasses import dataclass
from typing import Optional

try:
    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.common.exceptions import TimeoutException, WebDriverException
except Exception:  # pragma: no cover
    webdriver = None  # type: ignore


class BiliBiliCookieManager:
    """Cookie manager for multiple Bilibili accounts.
    
    Files stored as:
    - bilibili_cookies.json (default)
    - bilibili_cookies_<account>.json
    """
    def __init__(self, base_dir: str):
        self.base_dir = base_dir
        self.default_name = "bilibili_cookies.json"
    
    def _path_for(self, account: str | None) -> str:
        if not account or account in ("default", ""):
            return os.path.join(self.base_dir, self.default_name)
        filename = f"bilibili_cookies_{account}.json"
        return os.path.join(self.base_dir, filename)
    
    def list_accounts(self) -> list:
        """List all available cookie accounts."""
        files = []
        try:
            if not os.path.exists(self.base_dir):
                return files
            for fn in os.listdir(self.base_dir):
                if fn.startswith("bilibili_cookies") and fn.endswith(".json"):
                    if fn == self.default_name:
                        files.append(None)
                    else:
                        suffix = fn[len("bilibili_cookies_"):-5]
                        files.append(suffix)
        except Exception:
            pass
        return files
    
    def load_cookies(self, account: str | None = None) -> list:
        """Load cookies from file and sanitize for Selenium."""
        path = self._path_for(account)
        if not os.path.exists(path):
            return []
        try:
            with open(path, 'r', encoding='utf-8') as f:
                cookies = json.load(f)
                sanitized = []
                for c in cookies:
                    nc = {}
                    if 'name' in c and 'value' in c:
                        nc['name'] = c['name']
                        nc['value'] = c['value']
                    else:
                        continue
                    for k in ('domain', 'path', 'expiry', 'secure', 'httpOnly'):
                        if k in c:
                            if k in ('secure', 'httpOnly'):
                                try:
                                    nc[k] = bool(c[k])
                                except Exception:
                                    nc[k] = c[k]
                            else:
                                nc[k] = c[k]
                    sanitized.append(nc)
                return sanitized
        except Exception:
            return []
    
    def save_cookies(self, driver, account: str | None = None) -> None:
        """Save cookies from driver to file."""
        path = self._path_for(account)
        try:
            os.makedirs(os.path.dirname(path), exist_ok=True)
            cookies = driver.get_cookies()
            print(f"🍪 获取到 {len(cookies)} 个 cookies，保存到: {path}")
            with open(path, 'w', encoding='utf-8') as f:
                json.dump(cookies, f, ensure_ascii=False, indent=2)
            print(f"✓ Cookies 成功保存到文件: {path}")
        except Exception as e:
            print(f"❌ 保存 cookies 失败: {e}")
            raise  # 重新抛出异常以便调试


@dataclass
class BilibiliConfig:
    headless: bool = False
    cookie_dir: Optional[str] = os.getenv("BILIBILI_COOKIE_DIR")
    wait_timeout: int = int(os.getenv("BILIBILI_WAIT_TIMEOUT", "30"))
    keep_browser_open: bool = os.getenv("BILIBILI_KEEP_BROWSER_OPEN", "false").lower() in ("true", "1")


class BiliBiliPoster:
    """Bilibili video upload automation - Login functionality only."""
    
    def __init__(self, config: BilibiliConfig | None = None, account: str | None = None):
        self.config = config or BilibiliConfig()
        self.account = account
        self.driver = None
        
        # Cookie manager
        if self.config.cookie_dir:
            self._cookie_manager = BiliBiliCookieManager(self.config.cookie_dir)
        else:
            self._cookie_manager = None
    
    def _build_driver(self):
        """Build Chrome WebDriver instance."""
        if webdriver is None:
            raise RuntimeError("selenium not available - install selenium & a matching chromedriver")
        
        options = Options()
        if self.config.headless:
            options.add_argument("--headless=new")
        options.add_argument("--disable-gpu")
        options.add_argument("--no-sandbox")
        options.add_argument("--disable-dev-shm-usage")
        options.add_argument("--window-size=1280,900")
        
        driver = webdriver.Chrome(options=options)
        return driver
    
    def ensure_driver(self):
        """Ensure WebDriver is available."""
        if self.driver is None:
            self.driver = self._build_driver()
        return self.driver
    
    def _load_cookies(self):
        """Load cookies from file if cookie_manager is available."""
        if not self._cookie_manager:
            return
        
        cookies = self._cookie_manager.load_cookies(self.account)
        if not cookies:
            print("⚠️ 没有找到有效的 cookies")
            return
        
        print(f"🍪 准备加载 {len(cookies)} 个 cookies...")
        
        try:
            d = self.ensure_driver()
            
            successful_cookies = 0
            failed_cookies = 0
            
            for cookie in cookies:
                try:
                    # 检查 cookie 是否过期
                    if 'expiry' in cookie:
                        if cookie['expiry'] < time.time():
                            print(f"⏰ Cookie {cookie.get('name', 'unknown')} 已过期，跳过")
                            continue
                    
                    d.add_cookie(cookie)
                    successful_cookies += 1
                    
                except Exception as e:
                    failed_cookies += 1
                    print(f"❌ 添加 cookie 失败: {cookie.get('name', 'unknown')} - {e}")
            
            print(f"📊 Cookie 加载结果: 成功 {successful_cookies}, 失败 {failed_cookies}")
            
            # 刷新页面以应用cookies
            if successful_cookies > 0:
                print("🔄 刷新页面以应用cookies...")
                d.refresh()
                time.sleep(2)
            
        except Exception as e:
            print(f"❌ Cookie 加载过程出错: {e}")
    
    def _save_cookies(self):
        """Save cookies to file if cookie_manager is available."""
        if not self._cookie_manager:
            print("⚠️ Cookie管理器未初始化，无法保存cookies")
            return
        try:
            self._cookie_manager.save_cookies(self.driver, self.account)
        except Exception as e:
            print(f"❌ 保存 cookies 失败: {e}")
    
    def _is_logged_in(self) -> bool:
        """Check if user is logged in to Bilibili."""
        d = self.ensure_driver()
        try:
            print("🔍 检查登录状态...")
            
            # 检查登录状态的几种方式
            login_indicators = [
                ".bili-avatar-img",  # 头像
                ".nav-user-info",   # 用户信息
                ".header-avatar-wrap",  # 头像包装器
                ".nav-user-info-menu",  # 用户信息菜单
                ".t-center.no-select"  # 用户名区域
            ]
            
            for indicator in login_indicators:
                try:
                    elements = d.find_elements(By.CSS_SELECTOR, indicator)
                    if elements:
                        visible_elements = [el for el in elements if el.is_displayed()]
                        if visible_elements:
                            print(f"✓ 检测到登录状态指示器: {indicator} (找到{len(visible_elements)}个可见元素)")
                            return True
                except Exception as e:
                    print(f"❌ 检查指示器 {indicator} 时出错: {e}")
                    continue
            
            # 检查是否有登录按钮（未登录状态）
            try:
                login_btn = d.find_elements(By.CSS_SELECTOR, ".header-login-entry")
                if login_btn and any(btn.is_displayed() for btn in login_btn):
                    print("❌ 检测到登录按钮，用户未登录")
                    return False  # 有登录按钮说明未登录
            except Exception:
                pass
            
            # 额外检查：查看当前URL和页面内容
            current_url = d.current_url
            print(f"📍 当前页面URL: {current_url}")
            
            # 如果在创作中心页面，通常意味着已登录
            if "member.bilibili.com" in current_url or "space.bilibili.com" in current_url:
                # 检查页面是否包含用户相关内容
                try:
                    page_source = d.page_source
                    if any(keyword in page_source for keyword in ["用户名", "退出登录", "个人中心", "创作中心"]):
                        print("✓ 页面内容显示已登录")
                        return True
                except Exception:
                    pass
            
            print("❌ 未检测到登录状态")
            return False
        except Exception as e:
            print(f"❌ 登录状态检查出错: {e}")
            return False
    
    def login(self, max_wait: int | None = None):
        """
        Open Bilibili and ensure user is logged in.
        
        Strategy:
        1. Open browser and go to upload page
        2. Try loading cookies first (if cookie_manager available)
        3. Check login status
        4. If not logged in, wait for manual login
        5. Save cookies after successful login
        """
        d = self.ensure_driver()
        
        # 首先打开B站上传页面
        print("🌐 打开B站上传页面...")
        d.get("https://member.bilibili.com/platform/upload/video/frame?page_from=creative_home_top_upload")
        time.sleep(2)
        
        # 尝试加载 cookies
        self._load_cookies()
        
        # 检查是否已登录
        if self._is_logged_in():
            print("✓ 已登录B站")
            return True
        
        print("❌ 未检测到登录状态，请手动登录...")
        
        # 等待用户手动登录
        timeout = max_wait or self.config.wait_timeout or 180
        end_time = time.time() + timeout
        
        while time.time() < end_time:
            if self._is_logged_in():
                print("✓ 登录成功！")
                # 保存 cookies
                self._save_cookies()
                return True
            time.sleep(2)
        
        # 最后检查一次
        is_logged = self._is_logged_in()
        if is_logged:
            self._save_cookies()
        
        return is_logged
    
    def quit(self):
        """Close the browser."""
        if self.driver:
            try:
                self.driver.quit()
            except Exception:
                pass
            finally:
                self.driver = None